package devices

import (
	"context"
	"devops-super/internal/consts"
	"devops-super/internal/dao"
	"devops-super/internal/model/mymodel"
	"devops-super/internal/service"
	"devops-super/utility/util/timeUtil"
	"encoding/json"
	"errors"
	"github.com/gogf/gf/v2/os/gtime"
	"github.com/gogf/gf/v2/util/gconv"
	"strings"
	"time"
)

// GetTableStr 拼接分布式表字符串
func (s *sDevice) GetTableStr(ctx context.Context, flag string, deviceGroupId int64, timeS, timeE int64) (out string) {

	t1 := time.Unix(timeS, 0)
	// 格式化为 YYYYMMDDHHIISS 形式
	timeSformat := t1.Local().Format("20060102150405")
	t2 := time.Unix(timeE, 0)
	// 格式化为 YYYYMMDDHHIISS 形式
	timeEformat := t2.Local().Format("20060102150405")

	// 不格式化存储 因为时差关系 会造成误解，但是可读性会差了一点

	out = flag + "_" + gconv.String(deviceGroupId) + "_" + timeSformat + "_" + timeEformat
	return
}

// GetDeviceCurrentDistributeTableInfo 获取设备当前应该存放的分布式表
func (s *sDevice) GetDeviceCurrentDistributeTableInfo(ctx context.Context, deviceNo string, sampletime int64, flag string, forceCreate bool) (res *mymodel.DistributeTableResponse, err error) {
	savePolicy, err := s.GetDeviceNowSavePolicy(ctx, deviceNo)
	if err != nil {
		return nil, err
	}
	if savePolicy == nil {
		err = errors.New("save policy is nil")
		return nil, err
	}

	// 如果是评级 默认是按1年1存  按需求了解是数据不多
	if flag == consts.AeDistributeTableFlagAeLv {
		savePolicy.TimeBy = 1
	}

	var start, end int64
	switch savePolicy.TimeBy {
	case 1:
		start, end = timeUtil.ConvertToClosestYearTimestamp(sampletime)
	case 2:
		start, end = timeUtil.ConvertToClosestMonthTimestamp(sampletime)
	case 3:
		start, end = timeUtil.ConvertToClosestDayTimestamp(sampletime)
	case 4:
		start, end = timeUtil.ConvertToClosestHourTimestamp(sampletime)
	default:
		savePolicy.TimeBy = 1 //默认按一年
		start, end = timeUtil.ConvertToClosestYearTimestamp(sampletime)
	}
	deviceInfo, err := service.Device().GetByDeviceNo(ctx, deviceNo)
	if err != nil {
		return nil, err
	}
	dbConn := deviceInfo.DatabaseServer
	//生成数据表
	table := s.GetTableStr(ctx, flag, deviceInfo.GroupId, start, end)
	res, _ = service.DistributeTables().GetOneByDbConnAndTable(ctx, dbConn, table)
	if res == nil || res.Id == 0 {
		if savePolicy.ExpireTime <= 1 {
			savePolicy.ExpireTime = 1
		}
		if savePolicy.ExpireTime > 3650 {
			savePolicy.ExpireTime = 3650
		}
		expireAt := end + int64(savePolicy.ExpireTime*24*60*60)

		res = &mymodel.DistributeTableResponse{
			TimeBy:        savePolicy.TimeBy,
			TimeStart:     uint64(start),
			TimeEnd:       uint64(end),
			ServerKey:     dbConn,
			Table:         table,
			Flag:          flag,
			CreatedAt:     gtime.Now(),
			UpdatedAt:     nil,
			IsExpire:      1,
			ExpireTime:    expireAt,
			TotalAmount:   0,
			TotalSize:     0,
			DeviceGroupId: deviceInfo.GroupId,
			DeptId:        int64(deviceInfo.DeptId),
		}
		if forceCreate {
			// 同时需要去创建该表
			err = s.CreateDeviceDistributeDataTable(ctx, res)
			if err != nil {
				return nil, err
			}
			insertId, err := dao.AppDistributeTables.Ctx(ctx).InsertAndGetId(res)
			if err != nil {
				return nil, err
			}
			res.Id = insertId
		}
	}
	return
}

// GetAllDistributeTablesByWhere 条件获取分布式表
func (s *sDevice) GetAllDistributeTablesByWhere(ctx context.Context, where *mymodel.SearchDistributeTablesObj) (res []*mymodel.DistributeTableResponse, err error) {
	res = make([]*mymodel.DistributeTableResponse, 0)
	cols := dao.AppDistributeTables.Columns()
	m := dao.AppDistributeTables.Ctx(ctx)
	if where.Id > 0 {
		m = m.Where(cols.Id, where.Id)
	} else {
		m = m.Where(cols.Flag, where.Flag).Where(cols.DeviceGroupId, where.DeviceGroupId)
		// 结束时间比查询起始大 同时 起始时间比查询结束小 就满足要求
		m = m.Where(
			m.Builder().Where(cols.TimeEnd+">=", gconv.Int(where.TimeStart)).
				Where(cols.TimeStart+"<=", gconv.Int(where.TimeEnd)),
		)
	}
	err = m.Scan(&res)
	return
}

func (s *sDevice) GetAeDataCacheFormatType(ctx context.Context, domain int, direction int) (res string) {
	return gconv.String(domain) + "_" + gconv.String(direction)
}

// GetDistributeTableFlagByProductKey  获取表flag
// 只针对参数数据类型   如果是波形或者评级等就不可用
func (s *sDevice) GetDistributeTableFlagByProductKey(ctx context.Context, productKey string) (res string) {
	res = consts.AeDistributeTableFlagNone
	switch productKey {
	case consts.ProductKeyM1:
		res = consts.AeDistributeTableFlagAeParam
	case consts.ProductKeyM2:
		res = consts.AeDistributeTableFlagAeParam
	case consts.ProductKeyVI1:
		res = consts.AeDistributeTableFlagViParam
	case consts.ProductKeyVI2:
		res = consts.AeDistributeTableFlagViParam
	case consts.ProductKeyM1V1:
		res = consts.AeDistributeTableFlagAeViParam
	case consts.ProductKeyM1V2:
		res = consts.AeDistributeTableFlagAeViParam
	case consts.ProductKeyM2V1:
		res = consts.AeDistributeTableFlagAeViParam
	case consts.ProductKeyM2V2:
		res = consts.AeDistributeTableFlagAeViParam
	default:
		return res
	}
	return
}

// GetReplaceDistributeTableName 分布式表名的结构为 flag deviceGroupId times  timee
func (s *sDevice) GetReplaceDistributeTableName(ctx context.Context, table string, flag string) (res string) {
	parts := strings.Split(table, "_")
	// 替换第1段
	if len(parts) > 0 {
		parts[0] = flag
	}
	res = strings.Join(parts, "_")
	return
}

// CreateDeviceDistributeDataTable 创建分布式data表
func (s *sDevice) CreateDeviceDistributeDataTable(ctx context.Context, in *mymodel.DistributeTableResponse) (err error) {
	if in == nil {
		err = errors.New("input DistributeTableResponse is nil")
		return
	}
	switch in.Flag {
	case consts.AeDistributeTableFlagAeParam:
		err := s.CreateAeParamDataTable(ctx, in.ServerKey, in.Table)
		if err != nil {
			return err
		}
	case consts.AeDistributeTableFlagViParam:
		err := s.CreateVIParamDataTable(ctx, in.ServerKey, in.Table)
		if err != nil {
			return err
		}
	case consts.AeDistributeTableFlagAeViParam:
		err := s.CreateAeVIParamDataTable(ctx, in.ServerKey, in.Table)
		if err != nil {
			return err
		}
	case consts.AeDistributeTableFlagAeWave:
		//要创建一个临时表
		err = s.CreateAeTemplateWaveTable(ctx, in.ServerKey, consts.DistributeTableAeWaveTemplate)
		if err != nil {
			return err
		}
		err = s.CreateAeWaveTable(ctx, in.ServerKey, in.Table)
		if err != nil {
			return err
		}
	case consts.AeDistributeTableFlagViwave:
		//要创建一个临时表
		err = s.CreateViTemplateWaveTable(ctx, in.ServerKey, consts.DistributeTableViWaveTemplate)
		if err != nil {
			return err
		}
		err := s.CreateViWaveTable(ctx, in.ServerKey, in.Table)
		if err != nil {
			return err
		}
	}
	return
}

// GetDeviceNowReceivePolicy 获取设备当前的接收决策
func (s *sDevice) GetDeviceNowReceivePolicy(ctx context.Context, deviceNo string) (conf *mymodel.ProductDeptConfigReceivePolicy, err error) {
	deviceInfo, err := s.GetByDeviceNo(ctx, deviceNo)
	if err != nil {
		return nil, err
	}
	configStr, err := service.ProductDeptConfig().GetConfigByKey(ctx, deviceInfo.ProductId, int64(deviceInfo.DeptId),
		consts.ProductDeptConfigGroupReceivePolicy, consts.ProductDeptConfigKeyReceivePolicy)
	if configStr == "" || err != nil {
		err = errors.New("ReceivePolicyConfig not found")
		return
	}
	err = json.Unmarshal([]byte(configStr), &conf)
	if err != nil {
		return
	}
	return
}

// GetDeviceNowSavePolicy 获取设备当前的存储决策
func (s *sDevice) GetDeviceNowSavePolicy(ctx context.Context, deviceNo string) (conf *mymodel.ProductDeptConfigSavePolicy, err error) {
	deviceInfo, err := s.GetByDeviceNo(ctx, deviceNo)
	if err != nil {
		return nil, err
	}
	configStr, err := service.ProductDeptConfig().GetConfigByKey(ctx, deviceInfo.ProductId, int64(deviceInfo.DeptId),
		consts.ProductDeptConfigGroupSavePolicy, consts.ProductDeptConfigKeySavePolicy)

	if configStr == "" || err != nil {
		err = errors.New("SavePolicyConfig not found")
		return
	}
	err = json.Unmarshal([]byte(configStr), &conf)
	if err != nil {
		return
	}
	return
}
